/**
 * 资源监控工具
 * 监控系统资源使用情况，并在需要时进行自动调整和限制
 */
const os = require('os');
const v8 = require('v8');
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const logger = require('../utils/logger');

// 确保日志目录存在
const logDir = path.join(__dirname, '../../logs/monitoring');
if (!fs.existsSync(logDir)) {
  fs.mkdirSync(logDir, { recursive: true });
}

// 监控配置
const monitorConfig = {
  // 检查频率（毫秒）
  interval: 60000, // 1分钟

  // 内存阈值
  memory: {
    warning: 75, // 使用超过75%时发出警告
    critical: 85, // 使用超过85%时采取措施
    action: 90 // 使用超过90%时采取紧急措施
  },

  // CPU阈值
  cpu: {
    warning: 70, // 使用超过70%时发出警告
    critical: 85, // 使用超过85%时采取措施
    action: 95 // 使用超过95%时采取紧急措施
  },

  // 磁盘空间阈值 (GB)
  disk: {
    warning: 5, // 剩余小于5GB时发出警告
    critical: 2, // 剩余小于2GB时采取措施
    action: 1 // 剩余小于1GB时采取紧急措施
  },

  // WhatsApp浏览器实例限制
  whatsappInstances: {
    maxActive: 5, // 最大同时活跃实例数
    resourcePerInstance: 200 // 每个实例估计内存占用(MB)
  }
};

// 监控状态
const monitorState = {
  isRunning: false,
  startTime: null,
  currentAction: null,
  warningCount: 0,
  criticalCount: 0,
  lastResourceReport: null
};

// 检查CPU使用率
const checkCPU = async () => {
  return new Promise((resolve) => {
    if (os.platform() === 'win32') {
      // Windows平台
      exec('powershell "Get-Counter \\"\\\\Processor(_Total)\\\\% Processor Time\\" | Select-Object -ExpandProperty CounterSamples | Select-Object -ExpandProperty CookedValue"', (error, stdout) => {
        if (error) {
          logger.error('获取CPU使用率失败', { error });
          resolve({ usage: 0, info: null, error: error.message });
          return;
        }
        
        const usage = parseFloat(stdout.trim());
        resolve({ usage, info: { cores: os.cpus().length, load: os.loadavg() } });
      });
    } else {
      // Linux/macOS平台
      exec('top -bn1 | grep "Cpu(s)" | sed "s/.*, *\\([0-9.]*\\)%* id.*/\\1/" | awk \'{print 100 - $1}\'', (error, stdout) => {
        if (error) {
          logger.error('获取CPU使用率失败', { error });
          resolve({ usage: 0, info: null, error: error.message });
          return;
        }
        
        const usage = parseFloat(stdout.trim());
        resolve({ usage, info: { cores: os.cpus().length, load: os.loadavg() } });
      });
    }
  });
};

// 检查内存使用情况
const checkMemory = () => {
  const totalMemory = os.totalmem();
  const freeMemory = os.freemem();
  const usedMemory = totalMemory - freeMemory;
  const usagePercent = Math.round((usedMemory / totalMemory) * 100);
  
  // V8堆内存情况
  const v8HeapStats = v8.getHeapStatistics();
  
  return {
    usage: usagePercent,
    info: {
      total: Math.round(totalMemory / 1024 / 1024) + ' MB',
      free: Math.round(freeMemory / 1024 / 1024) + ' MB',
      used: Math.round(usedMemory / 1024 / 1024) + ' MB',
      v8: {
        heapTotal: Math.round(v8HeapStats.total_heap_size / 1024 / 1024) + ' MB',
        heapUsed: Math.round(v8HeapStats.used_heap_size / 1024 / 1024) + ' MB',
        heapLimit: Math.round(v8HeapStats.heap_size_limit / 1024 / 1024) + ' MB'
      }
    }
  };
};

// 检查磁盘空间使用情况
const checkDiskSpace = async () => {
  return new Promise((resolve) => {
    if (os.platform() === 'win32') {
      // Windows平台
      const currentDrive = process.cwd().split(path.sep)[0] || 'C:';
      exec(`powershell "Get-Volume ${currentDrive} | Select-Object -Property DriveLetter,Size,SizeRemaining | ConvertTo-Json"`, (error, stdout) => {
        if (error) {
          logger.error('获取磁盘空间失败', { error });
          resolve({ freespace: 0, info: null, error: error.message });
          return;
        }
        
        try {
          const driveInfo = JSON.parse(stdout.trim());
          const freeGB = Math.round(driveInfo.SizeRemaining / 1024 / 1024 / 1024 * 100) / 100;
          const totalGB = Math.round(driveInfo.Size / 1024 / 1024 / 1024 * 100) / 100;
          
          resolve({
            freespace: freeGB,
            info: {
              drive: driveInfo.DriveLetter,
              total: totalGB + ' GB',
              free: freeGB + ' GB',
              used: (totalGB - freeGB) + ' GB',
              usagePercent: Math.round((1 - freeGB / totalGB) * 100) + '%'
            }
          });
        } catch (parseError) {
          logger.error('解析磁盘信息失败', { error: parseError, stdout });
          resolve({ freespace: 0, info: null, error: parseError.message });
        }
      });
    } else {
      // Linux/macOS平台
      const appDir = process.cwd();
      exec(`df -h ${appDir} | awk 'NR==2 {print $2,$3,$4,$5}'`, (error, stdout) => {
        if (error) {
          logger.error('获取磁盘空间失败', { error });
          resolve({ freespace: 0, info: null, error: error.message });
          return;
        }
        
        try {
          const [total, used, free, usagePercent] = stdout.trim().split(' ');
          
          // 提取数字并转换为GB
          const extractGB = (value) => {
            const num = parseFloat(value);
            const unit = value.replace(/[0-9.]/g, '').toUpperCase();
            
            if (unit === 'T') return num * 1024;
            if (unit === 'G') return num;
            if (unit === 'M') return num / 1024;
            if (unit === 'K') return num / 1024 / 1024;
            return num;
          };
          
          const freeGB = extractGB(free);
          
          resolve({
            freespace: freeGB,
            info: {
              path: appDir,
              total,
              used,
              free,
              usagePercent
            }
          });
        } catch (parseError) {
          logger.error('解析磁盘信息失败', { error: parseError, stdout });
          resolve({ freespace: 0, info: null, error: parseError.message });
        }
      });
    }
  });
};

// 检查WhatsApp实例使用情况
const checkWhatsappInstances = async () => {
  return new Promise((resolve) => {
    if (os.platform() === 'win32') {
      // Windows平台 - 检查Chrome实例
      exec('powershell "Get-Process chrome | Measure-Object | Select-Object -ExpandProperty Count"', (error, stdout) => {
        if (error) {
          logger.error('获取Chrome进程数失败', { error });
          resolve({ count: 0, info: null, error: error.message });
          return;
        }
        
        const count = parseInt(stdout.trim()) || 0;
        
        // 估算内存使用
        const estimatedMemory = count * monitorConfig.whatsappInstances.resourcePerInstance;
        
        resolve({
          count,
          info: {
            active: count,
            estimatedMemory: estimatedMemory + ' MB'
          }
        });
      });
    } else {
      // Linux/macOS平台
      exec('ps aux | grep -i chrome | grep -v grep | wc -l', (error, stdout) => {
        if (error) {
          logger.error('获取Chrome进程数失败', { error });
          resolve({ count: 0, info: null, error: error.message });
          return;
        }
        
        const count = parseInt(stdout.trim()) || 0;
        
        // 估算内存使用
        const estimatedMemory = count * monitorConfig.whatsappInstances.resourcePerInstance;
        
        resolve({
          count,
          info: {
            active: count,
            estimatedMemory: estimatedMemory + ' MB'
          }
        });
      });
    }
  });
};

// 采取内存优化措施
const optimizeMemory = async (level) => {
  logger.info(`采取内存优化措施: ${level}`);
  
  if (level === 'warning') {
    // 非紧急措施：触发垃圾回收
    if (global.gc) {
      logger.info('手动触发垃圾回收');
      global.gc();
    }
  } else if (level === 'critical') {
    // 紧急措施：限制WhatsApp实例数
    logger.warn('内存使用临界，正在检查并限制WhatsApp实例');
    
    // 这里应通过应用API来限制实例，示例代码:
    try {
      const maxAllowedInstances = Math.max(1, Math.floor(monitorConfig.whatsappInstances.maxActive / 2));
      logger.info(`正在限制WhatsApp实例数为${maxAllowedInstances}`);
      
      // 实际实现中，应调用应用程序中的限制函数
      // await limitWhatsappInstances(maxAllowedInstances);
    } catch (error) {
      logger.error('限制WhatsApp实例失败', { error });
    }
  } else if (level === 'action') {
    // 紧急措施：关闭非活跃连接
    logger.error('内存状况严重，正在关闭非活跃连接和缓存');
    
    // 清理缓存
    if (global.gc) {
      logger.info('强制清理内存');
      global.gc();
      global.gc();
    }
    
    // 实际实现中，应调用应用程序中的优化函数
    // await forceCloseInactiveConnections();
    // await clearCaches();
  }
};

// 采取CPU优化措施
const optimizeCPU = async (level) => {
  logger.info(`采取CPU优化措施: ${level}`);
  
  if (level === 'warning') {
    // 非紧急措施：记录高CPU任务
    logger.info('CPU使用率较高，记录当前活动任务');
    
    // 实际实现中，可以收集当前活跃任务信息
  } else if (level === 'critical') {
    // 紧急措施：推迟非关键任务
    logger.warn('CPU使用率临界，推迟非关键任务');
    
    // 实际实现中，应调用应用程序中的任务管理API
    // await pauseNonCriticalTasks();
  } else if (level === 'action') {
    // 紧急措施：终止某些请求处理
    logger.error('CPU状况严重，正在限制请求处理');
    
    // 实际实现中，应调用应用程序中的限流机制
    // await enableStrictRateLimiting();
  }
};

// 采取磁盘空间优化措施
const optimizeDiskSpace = async (level) => {
  logger.info(`采取磁盘空间优化措施: ${level}`);
  
  if (level === 'warning') {
    // 非紧急措施：清理旧日志
    logger.info('磁盘空间不足，清理旧日志文件');
    
    // 清理旧日志
    try {
      // 清理超过7天的日志
      const logsDir = path.join(__dirname, '../../logs');
      
      // 在实际项目中，这部分需要根据实际日志文件命名规则实现
      const sevenDaysAgo = new Date();
      sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
      
      fs.readdir(logsDir, (err, files) => {
        if (err) {
          logger.error('读取日志目录失败', { error: err });
          return;
        }
        
        files.forEach(file => {
          const filePath = path.join(logsDir, file);
          fs.stat(filePath, (err, stats) => {
            if (err) {
              logger.error('获取文件信息失败', { file, error: err });
              return;
            }
            
            // 删除7天前的日志文件
            if (stats.isFile() && stats.mtime < sevenDaysAgo) {
              fs.unlink(filePath, err => {
                if (err) {
                  logger.error('删除旧日志文件失败', { file, error: err });
                } else {
                  logger.info('已删除旧日志文件', { file });
                }
              });
            }
          });
        });
      });
    } catch (error) {
      logger.error('清理旧日志失败', { error });
    }
  } else if (level === 'critical') {
    // 紧急措施：清理临时文件和缓存
    logger.warn('磁盘空间严重不足，清理临时文件和缓存');
    
    // 清理临时文件
    try {
      const tempDir = path.join(__dirname, '../../temp');
      if (fs.existsSync(tempDir)) {
        fs.readdir(tempDir, (err, files) => {
          if (err) {
            logger.error('读取临时目录失败', { error: err });
            return;
          }
          
          files.forEach(file => {
            const filePath = path.join(tempDir, file);
            fs.unlink(filePath, err => {
              if (err) {
                logger.error('删除临时文件失败', { file, error: err });
              } else {
                logger.info('已删除临时文件', { file });
              }
            });
          });
        });
      }
    } catch (error) {
      logger.error('清理临时文件失败', { error });
    }
  } else if (level === 'action') {
    // 紧急措施：拒绝文件上传
    logger.error('磁盘空间极度不足，禁用文件上传功能');
    
    // 实际实现中，应调用应用程序中的功能开关
    // await disableFileUploads();
  }
};

// 运行资源检查
const runResourceCheck = async () => {
  try {
    // 获取资源使用情况
    const [cpuResult, diskResult, whatsappResult] = await Promise.all([
      checkCPU(),
      checkDiskSpace(),
      checkWhatsappInstances()
    ]);
    
    const memoryResult = checkMemory();
    
    // 构建资源报告
    const report = {
      timestamp: new Date(),
      cpu: {
        usage: cpuResult.usage,
        info: cpuResult.info
      },
      memory: {
        usage: memoryResult.usage,
        info: memoryResult.info
      },
      disk: {
        freespace: diskResult.freespace,
        info: diskResult.info
      },
      whatsapp: {
        instances: whatsappResult.count,
        info: whatsappResult.info
      }
    };
    
    // 更新状态
    monitorState.lastResourceReport = report;
    
    // 记录资源状态
    logger.info('资源使用情况', {
      cpu: `${cpuResult.usage.toFixed(1)}%`,
      memory: `${memoryResult.usage}%`,
      disk: `${diskResult.freespace} GB可用`,
      whatsapp: `${whatsappResult.count}个实例`
    });
    
    // 检查阈值并采取措施
    // 1. 内存检查
    if (memoryResult.usage >= monitorConfig.memory.action) {
      logger.error('内存使用超过紧急阈值', { usage: memoryResult.usage });
      monitorState.criticalCount++;
      await optimizeMemory('action');
    } else if (memoryResult.usage >= monitorConfig.memory.critical) {
      logger.warn('内存使用超过临界阈值', { usage: memoryResult.usage });
      monitorState.criticalCount++;
      await optimizeMemory('critical');
    } else if (memoryResult.usage >= monitorConfig.memory.warning) {
      logger.info('内存使用超过警告阈值', { usage: memoryResult.usage });
      monitorState.warningCount++;
      await optimizeMemory('warning');
    }
    
    // 2. CPU检查
    if (cpuResult.usage >= monitorConfig.cpu.action) {
      logger.error('CPU使用超过紧急阈值', { usage: cpuResult.usage });
      monitorState.criticalCount++;
      await optimizeCPU('action');
    } else if (cpuResult.usage >= monitorConfig.cpu.critical) {
      logger.warn('CPU使用超过临界阈值', { usage: cpuResult.usage });
      monitorState.criticalCount++;
      await optimizeCPU('critical');
    } else if (cpuResult.usage >= monitorConfig.cpu.warning) {
      logger.info('CPU使用超过警告阈值', { usage: cpuResult.usage });
      monitorState.warningCount++;
      await optimizeCPU('warning');
    }
    
    // 3. 磁盘空间检查
    if (diskResult.freespace <= monitorConfig.disk.action) {
      logger.error('磁盘空间不足，达到紧急阈值', { free: diskResult.freespace });
      monitorState.criticalCount++;
      await optimizeDiskSpace('action');
    } else if (diskResult.freespace <= monitorConfig.disk.critical) {
      logger.warn('磁盘空间不足，达到临界阈值', { free: diskResult.freespace });
      monitorState.criticalCount++;
      await optimizeDiskSpace('critical');
    } else if (diskResult.freespace <= monitorConfig.disk.warning) {
      logger.info('磁盘空间不足，达到警告阈值', { free: diskResult.freespace });
      monitorState.warningCount++;
      await optimizeDiskSpace('warning');
    }
    
    // 4. WhatsApp实例检查
    if (whatsappResult.count > monitorConfig.whatsappInstances.maxActive) {
      logger.warn('WhatsApp实例数超过限制', {
        count: whatsappResult.count,
        max: monitorConfig.whatsappInstances.maxActive
      });
      
      // 实际实现中，应调用应用程序中的限制函数
      // await limitWhatsappInstances(monitorConfig.whatsappInstances.maxActive);
    }
    
  } catch (error) {
    logger.error('资源检查过程出错', { error });
  }
};

// 开始资源监控
const startMonitoring = async () => {
  if (monitorState.isRunning) {
    logger.info('监控已在运行中');
    return;
  }
  
  logger.info('启动资源监控');
  
  monitorState.isRunning = true;
  monitorState.startTime = new Date();
  monitorState.warningCount = 0;
  monitorState.criticalCount = 0;
  
  // 立即执行一次检查
  await runResourceCheck();
  
  // 设置定期检查
  const intervalId = setInterval(async () => {
    await runResourceCheck();
  }, monitorConfig.interval);
  
  // 保存定时器ID，以便稍后停止
  monitorState.intervalId = intervalId;
  
  logger.info('资源监控已启动', {
    interval: monitorConfig.interval + 'ms',
    thresholds: {
      memory: monitorConfig.memory,
      cpu: monitorConfig.cpu,
      disk: monitorConfig.disk
    }
  });
  
  return { success: true };
};

// 停止资源监控
const stopMonitoring = () => {
  if (!monitorState.isRunning) {
    logger.info('监控未运行');
    return { success: false, message: '监控未运行' };
  }
  
  clearInterval(monitorState.intervalId);
  
  monitorState.isRunning = false;
  monitorState.intervalId = null;
  
  logger.info('资源监控已停止', {
    duration: Date.now() - monitorState.startTime,
    warnings: monitorState.warningCount,
    criticals: monitorState.criticalCount
  });
  
  return { success: true };
};

// 获取当前监控状态
const getMonitoringStatus = () => {
  return {
    ...monitorState,
    uptime: monitorState.startTime ? Date.now() - monitorState.startTime : 0,
    config: monitorConfig
  };
};

// 如果直接运行此文件，启动监控
if (require.main === module) {
  startMonitoring().catch(error => {
    logger.error('启动监控失败', { error });
    process.exit(1);
  });
  
  // 处理进程信号
  process.on('SIGINT', () => {
    logger.info('收到中断信号，停止监控');
    stopMonitoring();
    process.exit(0);
  });
}

module.exports = {
  startMonitoring,
  stopMonitoring,
  getMonitoringStatus,
  checkCPU,
  checkMemory,
  checkDiskSpace,
  checkWhatsappInstances,
  monitorConfig,
  monitorState
}; 